import math

import moderngl
import pygame
from PIL import Image
from pygame.locals import OPENGL, DOUBLEBUF

from three import geometry, material, object3d, light, loader
from three.camera import Camera
from controller import OrbitController

pygame.init()


class Window:
    def __init__(self):
        info = pygame.display.Info()
        self.width = int(info.current_w / 2)
        self.height = int(info.current_h / 2)
        pygame.display.set_mode((self.width, self.height), DOUBLEBUF | OPENGL)
        self.ctx = moderngl.create_context()
        self.ctx.enable(moderngl.DEPTH_TEST | moderngl.CULL_FACE)

        self.camera = Camera(self.width / self.height, position=(0, 3, 6))
        self.controller = OrbitController(self.camera, self.width, self.height)

        _, tid = loader.load_texture(self.ctx, 'images/test.jpg')
        light_manager = light.LightManager()
        light_manager.add_light((1, 1, 1), strength=0.1)
        light_manager.add_point_light((1, 1, 0), (1, 0.2, 0), 1)
        light_manager.add_point_light((1, 1, 0), (-1, 0.1, 0), 1)
        plane = geometry.Plane(size=(5, 5), segments=(512, 512))
        self.o3d = object3d.Object3D(self.ctx, plane, material.LambertUVMapMaterial(diffuse_loc=tid))
        self.light_manager = light_manager

    def update(self, dt: float, wt: float, events):
        self.controller.update(dt, wt, events)

    def render(self):
        self.ctx.clear(0, 0, 0)
        self.o3d.render(self.camera, self.light_manager)
        pygame.display.flip()

    @staticmethod
    def quit():
        pygame.quit()

    def run(self, fps: int = 60):
        world_time: int = 0
        clock = pygame.time.Clock()
        while True:
            events = pygame.event.get()
            for event in events:
                if event.type == pygame.QUIT:
                    return self.quit()
                if event.type == pygame.KEYDOWN:
                    if event.key == 27:
                        return self.quit()
            dt = clock.get_time() / 1000
            world_time += dt
            self.update(dt, world_time, events)
            self.render()
            clock.tick(fps)


if __name__ == '__main__':
    Window().run(fps=144)
